From: Niki Roo Date: Mon, 4 May 2020 07:57:56 +0000 (+0200) Subject: move Navbar into nikiroo-utils X-Git-Url: https://git.nikiroo.be/?a=commitdiff_plain;h=e47e88eb1890632fdae5d5b0b0a84c2881a2c69b;p=fanfix-swing.git move Navbar into nikiroo-utils --- diff --git a/ui/NavBar.java b/ui/NavBar.java new file mode 100644 index 00000000..ba788f36 --- /dev/null +++ b/ui/NavBar.java @@ -0,0 +1,364 @@ +package be.nikiroo.utils.ui; + +import java.awt.Dimension; +import java.awt.LayoutManager; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.BoxLayout; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JTextField; + +/** + * A Swing-based navigation bar, that displays first/previous/next/last page + * buttons. + * + * @author niki + */ +public class NavBar extends ListenerPanel { + private static final long serialVersionUID = 1L; + + /** The event that is fired on page change. */ + public static final String PAGE_CHANGED = "page changed"; + + private JTextField page; + private JLabel maxPage; + private JLabel label; + + private int index = 0; + private int min = 0; + private int max = 0; + private String extraLabel = null; + + private JButton first; + private JButton previous; + private JButton next; + private JButton last; + + /** + * Create a new navigation bar. + *

+ * The minimum must be lower or equal to the maximum. + *

+ * Note than a max of "-1" means "infinite". + * + * @param min + * the minimum page number (cannot be negative) + * @param max + * the maximum page number (cannot be lower than min, except if + * -1 (infinite)) + * + * @throws IndexOutOfBoundsException + * if min > max and max is not "-1" + */ + public NavBar(int min, int max) { + if (min > max && max != -1) { + throw new IndexOutOfBoundsException( + String.format("min (%d) > max (%d)", min, max)); + } + + LayoutManager layout = new BoxLayout(this, BoxLayout.X_AXIS); + setLayout(layout); + + // Page navigation + first = new JButton(); + first.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + first(); + } + }); + + previous = new JButton(); + previous.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + previous(); + } + }); + + page = new JTextField(Integer.toString(min)); + page.setPreferredSize(new Dimension(page.getPreferredSize().width * 2, + page.getPreferredSize().height)); + page.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + try { + int pageNb = Integer.parseInt(page.getText()); + if (pageNb < NavBar.this.min || pageNb > NavBar.this.max) { + throw new NumberFormatException("invalid"); + } + + if (setIndex(pageNb)) + fireActionPerformed(PAGE_CHANGED); + } catch (NumberFormatException nfe) { + page.setText(Integer.toString(index + 1)); + } + } + }); + + maxPage = new JLabel(" of " + max); + + next = new JButton(); + next.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + next(); + } + }); + + last = new JButton(); + last.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + last(); + } + }); + + // Set the << < > >> "icons" + setIcons(null, null, null, null); + + this.add(first); + this.add(previous); + this.add(page); + this.add(maxPage); + this.add(next); + this.add(last); + + label = new JLabel(""); + this.add(label); + + this.min = min; + this.max = max; + this.index = min; + + updateEnabled(); + updateLabel(); + fireActionPerformed(PAGE_CHANGED); + } + + /** + * The current index, must be between {@link NavBar#min} and + * {@link NavBar#max}, both inclusive. + * + * @return the index + */ + public int getIndex() { + return index; + } + + /** + * The current index, must be between {@link NavBar#min} and + * {@link NavBar#max}, both inclusive. + * + * @param index + * the new index + * + * @return TRUE if the index changed + * + * @throws IndexOutOfBoundsException + * if the index is out of bounds according to + * {@link NavBar#getMin()} and {@link NavBar#getMax()}. + */ + public boolean setIndex(int index) { + if (index != this.index) { + if (index < min || (index > max && max != -1)) { + throw new IndexOutOfBoundsException(String.format( + "Index %d but min/max is [%d/%d]", index, min, max)); + } + + this.index = index; + updateLabel(); + updateEnabled(); + + return true; + } + + return false; + } + + /** + * The minimun page number. Cannot be negative. + * + * @return the min + */ + public int getMin() { + return min; + } + + /** + * The minimum page number. Cannot be negative. + *

+ * May update the index if needed (if the index is < the new min). + *

+ * Will also (always) update the label and enable/disable the required + * buttons. + * + * @param min + * the new min + */ + public void setMin(int min) { + this.min = min; + if (index < min) { + index = min; + } + + updateEnabled(); + updateLabel(); + } + + /** + * The maximum page number. Cannot be lower than min, except if -1 + * (infinite). + * + * @return the max + */ + public int getMax() { + return max; + } + + /** + * The maximum page number. Cannot be lower than min, except if -1 + * (infinite). + *

+ * May update the index if needed (if the index is > the new max). + *

+ * Will also (always) update the label and enable/disable the required + * buttons. + * + * @param max + * the new max + */ + public void setMax(int max) { + this.max = max; + if (index > max && max != -1) { + index = max; + } + + maxPage.setText(" of " + max); + updateEnabled(); + updateLabel(); + } + + /** + * The current extra label to display. + * + * @return the current label + */ + public String getExtraLabel() { + return extraLabel; + } + + /** + * The current extra label to display. + * + * @param currentLabel + * the new current label + */ + public void setExtraLabel(String currentLabel) { + this.extraLabel = currentLabel; + updateLabel(); + } + + /** + * Change the page to the next one. + * + * @return TRUE if it changed + */ + public boolean next() { + if (setIndex(index + 1)) { + fireActionPerformed(PAGE_CHANGED); + return true; + } + + return false; + } + + /** + * Change the page to the previous one. + * + * @return TRUE if it changed + */ + public boolean previous() { + if (setIndex(index - 1)) { + fireActionPerformed(PAGE_CHANGED); + return true; + } + + return false; + } + + /** + * Change the page to the first one. + * + * @return TRUE if it changed + */ + public boolean first() { + if (setIndex(min)) { + fireActionPerformed(PAGE_CHANGED); + return true; + } + + return false; + } + + /** + * Change the page to the last one. + * + * @return TRUE if it changed + */ + public boolean last() { + if (setIndex(max)) { + fireActionPerformed(PAGE_CHANGED); + return true; + } + + return false; + } + + /** + * Set icons for the buttons instead of square brackets. + *

+ * Any NULL value will make the button use square brackets again. + * + * @param first + * the icon of the button "go to first page" + * @param previous + * the icon of the button "go to previous page" + * @param next + * the icon of the button "go to next page" + * @param last + * the icon of the button "go to last page" + */ + public void setIcons(Icon first, Icon previous, Icon next, Icon last) { + this.first.setIcon(first); + this.first.setText(first == null ? "<<" : ""); + this.previous.setIcon(previous); + this.previous.setText(previous == null ? "<" : ""); + this.next.setIcon(next); + this.next.setText(next == null ? ">" : ""); + this.last.setIcon(last); + this.last.setText(last == null ? ">>" : ""); + } + + /** + * Update the label displayed in the UI. + */ + private void updateLabel() { + label.setText(getExtraLabel()); + page.setText(Integer.toString(index)); + } + + /** + * Update the navigation buttons "enabled" state according to the current + * index value. + */ + private void updateEnabled() { + first.setEnabled(index > min); + previous.setEnabled(index > min); + next.setEnabled(index < max || max == -1); + last.setEnabled(index < max || max == -1); + } +}