diff --git a/diylc/diylc-core/src/org/diylc/presenter/update.xml b/diylc/diylc-core/src/org/diylc/presenter/update.xml
index bfc2786e..25c68935 100644
--- a/diylc/diylc-core/src/org/diylc/presenter/update.xml
+++ b/diylc/diylc-core/src/org/diylc/presenter/update.xml
@@ -3421,7 +3421,19 @@
NEW_FEATURE
Português translation added (thanks Pedro Rizzi!)
-
+
+
+ NEW_FEATURE
+ Building blocks and Favorites added to the component toolbar
+
+
+ NEW_FEATURE
+ Scroll buttons added to the component toolbar that appear when needed
+
+
+ IMPROVEMENT
+ Save last selected tab in the component toolbar and restore it in the next session
+
IMPROVEMENT
When editing component properties, group Length and Width properties together
@@ -3432,7 +3444,7 @@
BUG_FIX
- Fixed some issues with exporting and importing building blocks and variants. If you still have issues, your variant/building block files might need to be manually updated to keep working
+ Fixed some issues with exporting/importing building blocks and variants. If you still have issues, your variant/building block files might need to be manually updated to keep working
https://github.com/bancika/diy-layout-creator/releases
diff --git a/diylc/diylc-swing/src/org/diylc/swing/plugins/toolbox/ActionMapAction.java b/diylc/diylc-swing/src/org/diylc/swing/plugins/toolbox/ActionMapAction.java
new file mode 100644
index 00000000..2acf31fc
--- /dev/null
+++ b/diylc/diylc-swing/src/org/diylc/swing/plugins/toolbox/ActionMapAction.java
@@ -0,0 +1,82 @@
+/*
+ *
+ * DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
+ *
+ * This file is part of DIYLC.
+ *
+ * DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with DIYLC. If not, see
+ * .
+ */
+package org.diylc.swing.plugins.toolbox;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JComponent;
+
+/*
+ * The ActionMapAction class is a convenience class that allows you to use an installed Action as an
+ * Action or ActionListener on a separate component.
+ *
+ * It can be used on components like JButton or JMenuItem that support an Action as a property of
+ * the component. Or it can be added to the same above components as an ActionListener.
+ *
+ * The benefit of this class is that a new ActionEvent will be created such that the source of the
+ * event is the component the Action belongs to, not the component that was "clicked". Otherwise in
+ * many cases a ClassCastException will be thrown when the Action is invoked.
+ */
+public class ActionMapAction extends AbstractAction {
+
+ private static final long serialVersionUID = 1L;
+
+ private Action originalAction;
+ private JComponent component;
+ private String actionCommand = "";
+ private int repeatCount;
+
+ /**
+ * Replace the default Action for the given KeyStroke with a custom Action
+ *
+ * @param name the name parameter of the Action
+ * @param componet the component the Action belongs to
+ * @param actionKey the key to identify the Action in the ActionMap
+ * @param repeatCount the number of time to repeat the same action on invocation
+ */
+ public ActionMapAction(String name, JComponent component, String actionKey, int repeatCount) {
+ super(name);
+ this.repeatCount = repeatCount;
+
+ originalAction = component.getActionMap().get(actionKey);
+
+ if (originalAction == null) {
+ String message = "no Action for action key: " + actionKey;
+ throw new IllegalArgumentException(message);
+ }
+
+ this.component = component;
+ }
+
+ public void setActionCommand(String actionCommand) {
+ this.actionCommand = actionCommand;
+ }
+
+ /**
+ * Invoke the original Action using the original component as the source of the event.
+ */
+ public void actionPerformed(ActionEvent e) {
+ e = new ActionEvent(component, ActionEvent.ACTION_PERFORMED, actionCommand, e.getWhen(),
+ e.getModifiers());
+
+ for (int i = 0; i < repeatCount; i++)
+ originalAction.actionPerformed(e);
+ }
+}
diff --git a/diylc/diylc-swing/src/org/diylc/swing/plugins/toolbox/ComponentButtonFactory.java b/diylc/diylc-swing/src/org/diylc/swing/plugins/toolbox/ComponentButtonFactory.java
index 643c00df..3c76df92 100644
--- a/diylc/diylc-swing/src/org/diylc/swing/plugins/toolbox/ComponentButtonFactory.java
+++ b/diylc/diylc-swing/src/org/diylc/swing/plugins/toolbox/ComponentButtonFactory.java
@@ -37,12 +37,15 @@ import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
+import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
+import org.apache.log4j.Logger;
import org.diylc.appframework.miscutils.Utils;
import org.diylc.common.ComponentType;
+import org.diylc.common.IBlockProcessor.InvalidBlockException;
import org.diylc.common.IPlugInPort;
import org.diylc.core.IDIYComponent;
import org.diylc.core.Template;
@@ -56,6 +59,8 @@ import org.diylc.swingframework.openide.DropDownButtonFactory;
* @author Branislav Stojkovic
*/
public class ComponentButtonFactory {
+
+ private static final Logger LOG = Logger.getLogger(ComponentButtonFactory.class);
public static int MARGIN = 3;
@@ -191,4 +196,35 @@ public class ComponentButtonFactory {
item.add(label);
return item;
}
+
+ public static JButton createBuildingBlockButton(final IPlugInPort plugInPort, final String blockName) {
+ JButton button = new JButton(blockName, IconLoader.Component.getIcon());
+
+ button.setVerticalTextPosition(SwingConstants.BOTTOM);
+ button.setHorizontalTextPosition(SwingConstants.CENTER);
+
+ button.setBorder(BorderFactory.createEmptyBorder(MARGIN + 1, MARGIN + 1, MARGIN, MARGIN));
+ button.setToolTipText("" + blockName + "
building block");
+
+ button.addActionListener(new ActionListener() {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ try {
+ plugInPort.loadBlock(blockName);
+ } catch (InvalidBlockException e1) {
+ LOG.error("Error loading building block", e1);
+ }
+ }
+ });
+
+ button.addKeyListener(new KeyAdapter() {
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ plugInPort.keyPressed(e.getKeyCode(), Utils.isMac() ? e.isControlDown() : e.isMetaDown(), e.isShiftDown(), e.isAltDown());
+ }
+ });
+ return button;
+ }
}
diff --git a/diylc/diylc-swing/src/org/diylc/swing/plugins/toolbox/ComponentTabbedPane.java b/diylc/diylc-swing/src/org/diylc/swing/plugins/toolbox/ComponentTabbedPane.java
index 9ac39644..ee7783f2 100644
--- a/diylc/diylc-swing/src/org/diylc/swing/plugins/toolbox/ComponentTabbedPane.java
+++ b/diylc/diylc-swing/src/org/diylc/swing/plugins/toolbox/ComponentTabbedPane.java
@@ -21,34 +21,37 @@
*/
package org.diylc.swing.plugins.toolbox;
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.Container;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Container;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
-import javax.swing.BoxLayout;
-import javax.swing.JMenuItem;
-import javax.swing.JPanel;
-import javax.swing.JPopupMenu;
-import javax.swing.JTabbedPane;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-import javax.swing.event.PopupMenuEvent;
-import javax.swing.event.PopupMenuListener;
+import javax.swing.BoxLayout;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JTabbedPane;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.PopupMenuEvent;
+import javax.swing.event.PopupMenuListener;
-import org.apache.log4j.Logger;
-import org.diylc.appframework.miscutils.ConfigurationManager;
-import org.diylc.appframework.miscutils.IConfigListener;
-import org.diylc.common.ComponentType;
-import org.diylc.common.IPlugInPort;
-import org.diylc.core.IDIYComponent;
-import org.diylc.core.Template;
-import org.diylc.presenter.ComparatorFactory;
+import org.apache.log4j.Logger;
+import org.diylc.appframework.miscutils.ConfigurationManager;
+import org.diylc.appframework.miscutils.IConfigListener;
+import org.diylc.common.ComponentType;
+import org.diylc.common.Favorite;
+import org.diylc.common.Favorite.FavoriteType;
+import org.diylc.common.IPlugInPort;
+import org.diylc.core.IDIYComponent;
+import org.diylc.core.Template;
+import org.diylc.lang.LangUtil;
+import org.diylc.presenter.ComparatorFactory;
import org.diylc.presenter.ComponentProcessor;
-import org.diylc.presenter.Presenter;
/**
* Tabbed pane that shows all available components categorized into tabs.
@@ -59,95 +62,128 @@ class ComponentTabbedPane extends JTabbedPane {
private static final long serialVersionUID = 1L;
- private static final Logger LOG = Logger.getLogger(ComponentTabbedPane.class);
-
- public static int SCROLL_STEP = Presenter.ICON_SIZE + ComponentButtonFactory.MARGIN * 2 + 2;
+ private static final Logger LOG = Logger.getLogger(ComponentTabbedPane.class);
+
+ public static String LAST_SELECTED_TAB = "lastSelectedTab";
private final IPlugInPort plugInPort;
private Container recentToolbar;
- private Container buildingBlocksToolbar;
- private List pendingRecentComponents = null;
-
+ private Container buildingBlocksToolbar;
+ private Container favoritesToolbar;
+
+ private Map typesByClass;
+
+ private List favorites;
+ private List pendingRecentComponents = null;
+ private List blocks;
+
public ComponentTabbedPane(IPlugInPort plugInPort) {
super();
- this.plugInPort = plugInPort;
- addTab("Recently Used", createRecentComponentsPanel());
-// addTab("Building Blocks", createBuildingBlocksPanel());
+ this.plugInPort = plugInPort;
+
+ initialize();
+
+ // layout UI
+ addTab(LangUtil.translate("(Favorites)"), createFavoritesPanel());
+ addTab(LangUtil.translate("(Recently Used)"), createRecentComponentsPanel());
+ addTab(LangUtil.translate("(Building Blocks)"), createBuildingBlocksPanel());
Map> componentTypes = plugInPort.getComponentTypes();
List categories = new ArrayList(componentTypes.keySet());
Collections.sort(categories);
for (String category : categories) {
JPanel panel = createTab((componentTypes.get(category)));
addTab(category, panel);
- }
+ }
+
+ // restore last selected tab
+ int lastSelectedTab = ConfigurationManager.getInstance().readInt(LAST_SELECTED_TAB, -1);
+ if (lastSelectedTab >= 0)
+ setSelectedIndex(lastSelectedTab);
+
addChangeListener(new ChangeListener() {
@Override
- public void stateChanged(ChangeEvent e) {
+ public void stateChanged(ChangeEvent e) {
+ ConfigurationManager.getInstance().writeValue(LAST_SELECTED_TAB, getSelectedIndex());
ComponentTabbedPane.this.plugInPort.setNewComponentTypeSlot(null, null, false);
// Refresh recent components if needed
if (pendingRecentComponents != null) {
- refreshRecentComponentsToolbar(getRecentToolbar(), pendingRecentComponents);
+ refreshRecentComponentsToolbar(pendingRecentComponents);
getRecentToolbar().invalidate();
pendingRecentComponents = null;
}
}
- });
+ });
+
+
+ }
+
+ @SuppressWarnings("unchecked")
+ private void initialize() {
+ Map> componentTypes = plugInPort.getComponentTypes();
+ this.typesByClass = new HashMap();
+ for (Map.Entry> e : componentTypes.entrySet())
+ for (ComponentType c : e.getValue())
+ typesByClass.put(c.getInstanceClass().getCanonicalName(), c);
+
+ // load building blocks
+ ConfigurationManager.getInstance().addConfigListener(IPlugInPort.BLOCKS_KEY,
+ new IConfigListener() {
+
+ @Override
+ public void valueChanged(String key, Object value) {
+ Map>> newBlocks =
+ (Map>>) value;
+ if (newBlocks != null) {
+ List blockNames = new ArrayList(newBlocks.keySet());
+ Collections.sort(blockNames);
+ if (!blockNames.equals(ComponentTabbedPane.this.blocks)) {
+ LOG.info("Detected block change");
+ ComponentTabbedPane.this.blocks = blockNames;
+ refreshBuildingBlocksToolbar();
+ } else
+ LOG.info("Detected no block change");
+ } else
+ LOG.info("Detected no block change");
+ }
+ });
+ Map>> newBlocks =
+ (Map>>) ConfigurationManager.getInstance()
+ .readObject(IPlugInPort.BLOCKS_KEY, null);
+ if (newBlocks == null)
+ this.blocks = new ArrayList();
+ else {
+ this.blocks = new ArrayList(newBlocks.keySet());
+ Collections.sort(this.blocks);
+ }
+
+ ConfigurationManager.getInstance().addConfigListener(IPlugInPort.FAVORITES_KEY,
+ new IConfigListener() {
+
+ @Override
+ public void valueChanged(String key, Object value) {
+ List newFavorites = (List) value;
+ if (newFavorites != null && !newFavorites.equals(ComponentTabbedPane.this.favorites)) {
+ LOG.info("Detected favorites change");
+ ComponentTabbedPane.this.favorites = new ArrayList(newFavorites);
+ refreshFavoritesToolbar();
+ } else
+ LOG.info("Detected no favorites change");
+ }
+ });
+ this.favorites = new ArrayList((List) ConfigurationManager.getInstance()
+ .readObject(IPlugInPort.FAVORITES_KEY, new ArrayList()));
}
private JPanel createTab(List componentTypes) {
JPanel panel = new JPanel(new BorderLayout());
- // final JScrollPane scrollPane =
- // createComponentScrollBar(componentTypes);
+
panel.setOpaque(false);
panel.add(createComponentPanel(componentTypes), BorderLayout.CENTER);
- // JButton leftButton = new JButton("<");
- // leftButton.addActionListener(new ActionListener() {
- //
- // @Override
- // public void actionPerformed(ActionEvent e) {
- // Rectangle rect = scrollPane.getVisibleRect();
- // if (rect.x > SCROLL_STEP) {
- // rect.translate(-SCROLL_STEP, 0);
- // } else {
- // rect.translate(-rect.x, 0);
- // }
- // }
- // });
- // leftButton.setMargin(new Insets(0, 2, 0, 2));
- // JButton rightButton = new JButton(">");
- // rightButton.addActionListener(new ActionListener() {
- //
- // @Override
- // public void actionPerformed(ActionEvent e) {
- // Rectangle rect = scrollPane.getVisibleRect();
- // if (rect.x + rect.width < scrollPane.getViewport().getSize().width -
- // SCROLL_STEP) {
- // rect.translate(SCROLL_STEP, 0);
- // } else {
- // rect.translate(scrollPane.getViewport().getSize().width - rect.x -
- // rect.width,
- // 0);
- // }
- // }
- // });
- // rightButton.setMargin(new Insets(0, 2, 0, 2));
- // panel.add(leftButton, BorderLayout.WEST);
- // panel.add(scrollPane);
- // panel.add(rightButton, BorderLayout.EAST);
+
return panel;
}
- // private JScrollPane createComponentScrollBar(List
- // componentTypes) {
- // JScrollPane scrollPane = new
- // JScrollPane(createComponentPanel(componentTypes));
- // scrollPane.setOpaque(false);
- // scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
- // scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
- // return scrollPane;
- // }
-
public Container getRecentToolbar() {
if (recentToolbar == null) {
recentToolbar = new Container();
@@ -162,6 +198,14 @@ class ComponentTabbedPane extends JTabbedPane {
buildingBlocksToolbar.setLayout(new BoxLayout(buildingBlocksToolbar, BoxLayout.X_AXIS));
}
return buildingBlocksToolbar;
+ }
+
+ public Container getFavoritesToolbar() {
+ if (favoritesToolbar == null) {
+ favoritesToolbar = new Container();
+ favoritesToolbar.setLayout(new BoxLayout(favoritesToolbar, BoxLayout.X_AXIS));
+ }
+ return favoritesToolbar;
}
private Component createComponentPanel(List componentTypes) {
@@ -177,18 +221,13 @@ class ComponentTabbedPane extends JTabbedPane {
}
}
- return toolbar;
+ return new ToolbarScrollPane(toolbar);
}
@SuppressWarnings("unchecked")
private Component createRecentComponentsPanel() {
- JPanel panel = new JPanel(new BorderLayout());
- panel.setOpaque(false);
-
final Container toolbar = getRecentToolbar();
- refreshRecentComponentsToolbar(
- toolbar,
- (List) ConfigurationManager.getInstance().readObject(IPlugInPort.RECENT_COMPONENTS_KEY,
+ refreshRecentComponentsToolbar((List) ConfigurationManager.getInstance().readObject(IPlugInPort.RECENT_COMPONENTS_KEY,
new ArrayList()));
ConfigurationManager.getInstance().addConfigListener(IPlugInPort.RECENT_COMPONENTS_KEY, new IConfigListener() {
@@ -200,40 +239,39 @@ class ComponentTabbedPane extends JTabbedPane {
}
});
- panel.add(toolbar, BorderLayout.CENTER);
+ JPanel panel = new ToolbarScrollPane(toolbar);
return panel;
}
- @SuppressWarnings("unused")
private Component createBuildingBlocksPanel() {
+ final Container toolbar = getBuildingBlocksToolbar();
+
+ JPanel panel = new ToolbarScrollPane(toolbar);
+
+ refreshBuildingBlocksToolbar();
+
+ return panel;
+ }
+
+ private Component createFavoritesPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setOpaque(false);
- final Container toolbar = getBuildingBlocksToolbar();
-// refreshRecentComponentsToolbar(
-// toolbar,
-// (List) ConfigurationManager.getInstance().readObject(IPlugInPort.RECENT_COMPONENTS_KEY,
-// new ArrayList()));
-// ConfigurationManager.getInstance().addConfigListener(IPlugInPort.RECENT_COMPONENTS_KEY, new IConfigListener() {
-//
-// @Override
-// public void valueChanged(String key, Object value) {
-// // Cache the new list, we'll refresh when there's a
-// // chance
-// pendingRecentComponents = (List) value;
-// }
-// });
+ final Container toolbar = getFavoritesToolbar();
panel.add(toolbar, BorderLayout.CENTER);
+
+ refreshFavoritesToolbar();
return panel;
}
@SuppressWarnings("unchecked")
- private void refreshRecentComponentsToolbar(Container toolbar, List recentComponentClassList) {
+ private void refreshRecentComponentsToolbar(List recentComponentClassList) {
+ Container toolbar = getRecentToolbar();
toolbar.removeAll();
for (String componentClassName : recentComponentClassList) {
ComponentType componentType;
@@ -247,6 +285,30 @@ class ComponentTabbedPane extends JTabbedPane {
LOG.error("Could not create recent component button for " + componentClassName, e);
}
}
+ }
+
+ private void refreshBuildingBlocksToolbar() {
+ Container toolbar = getBuildingBlocksToolbar();
+ toolbar.removeAll();
+ for (String block : this.blocks) {
+ Component button = ComponentButtonFactory.createBuildingBlockButton(plugInPort, block);
+ toolbar.add(button);
+ }
+ }
+
+ private void refreshFavoritesToolbar() {
+ Container toolbar = getFavoritesToolbar();
+ toolbar.removeAll();
+ for (Favorite fav : this.favorites) {
+ Component button;
+ if (fav.getType() == FavoriteType.Block) {
+ button = ComponentButtonFactory.createBuildingBlockButton(plugInPort, fav.getName());
+ } else {
+ ComponentType componentType = this.typesByClass.get(fav.getName());
+ button = ComponentButtonFactory.create(plugInPort, componentType, createVariantPopup(componentType));
+ }
+ toolbar.add(button);
+ }
}
private JPopupMenu createVariantPopup(final ComponentType componentType) {
diff --git a/diylc/diylc-swing/src/org/diylc/swing/plugins/toolbox/ToolbarScrollPane.java b/diylc/diylc-swing/src/org/diylc/swing/plugins/toolbox/ToolbarScrollPane.java
new file mode 100644
index 00000000..cbd9ca1f
--- /dev/null
+++ b/diylc/diylc-swing/src/org/diylc/swing/plugins/toolbox/ToolbarScrollPane.java
@@ -0,0 +1,77 @@
+/*
+ *
+ * DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
+ *
+ * This file is part of DIYLC.
+ *
+ * DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with DIYLC. If not, see
+ * .
+ */
+package org.diylc.swing.plugins.toolbox;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+
+import javax.swing.BorderFactory;
+import javax.swing.JPanel;
+import javax.swing.JScrollBar;
+import javax.swing.JScrollPane;
+import javax.swing.UIManager;
+import javax.swing.plaf.basic.BasicArrowButton;
+
+public class ToolbarScrollPane extends JPanel {
+
+ private static final long serialVersionUID = 1L;
+
+ private Component view;
+ private BasicArrowButton west;
+ private BasicArrowButton east;
+
+ public ToolbarScrollPane(Component view) {
+ this.view = view;
+ setOpaque(false);
+ setLayout(new BorderLayout());
+ setBorder(BorderFactory.createEmptyBorder());
+
+ JScrollPane scrollPane = new JScrollPane(view);
+ scrollPane.setBorder(BorderFactory.createEmptyBorder());
+ scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+ scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
+ add(scrollPane);
+
+ JScrollBar horizontal = scrollPane.getHorizontalScrollBar();
+
+ west = new BasicArrowButton(BasicArrowButton.WEST);
+ west.setAction(new ActionMapAction("", horizontal, "negativeUnitIncrement", 120));
+ west.setBorder(BorderFactory.createLineBorder(UIManager.getColor("Button.shadow")));
+ add(west, BorderLayout.WEST);
+
+ east = new BasicArrowButton(BasicArrowButton.EAST);
+ east.setAction(new ActionMapAction("", horizontal, "positiveUnitIncrement", 120));
+ east.setBorder(BorderFactory.createLineBorder(UIManager.getColor("Button.shadow")));
+ add(east, BorderLayout.EAST);
+
+ addComponentListener(new ComponentAdapter() {
+ @Override
+ public void componentResized(ComponentEvent e) {
+ refreshScrollButtonVisibility();
+ }
+ });
+ }
+
+ private void refreshScrollButtonVisibility() {
+ boolean needsScroll = getWidth() < view.getWidth();
+ west.setVisible(needsScroll);
+ east.setVisible(needsScroll);
+ }
+}