/*
* Copyright © 2010 Martin Riedel
*
* This file is part of TransFile.
*
* TransFile 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.
*
* TransFile 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 TransFile. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sourceforge.transfile.ui.swing;
import static net.sourceforge.transfile.ui.swing.StatusService.StatusMessage;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
/**
* <p>A small panel whose sole purpose is to display textual status messages upon request.</p>
*
* <p>Normally displays one message at a time but can be expanded to show more.</p>
*
* @author Martin Riedel
*
*/
public class StatusPanel extends TopLevelPanel {
private static final long serialVersionUID = 63220329611742114L;
/*
* The number of messages/lines to show in the expanded view without having to scroll
*/
private static final int maxMessages = 5;
/*
* True if the StatusPanel is in expanded mode
*/
private boolean isExpanded = false;
/*
* The number of pixels to add to / subtract from the current size of the StatusPanel when expanding/un-expanding
*/
private static final int expandBy = 50;
/*
* Custom JList holding the messages
*/
private StatusList statusList;
/*
* JScrollPane wrapping StatusList
*/
JScrollPane statusListScrollPane;
/*
* "more" / "less" buttons
*/
private JButton expandButton;
private JButton unexpandButton;
/**
* Creates a StatusPanel
* @param window
* <br>Should not be null
* <br>Shared parameter
*/
public StatusPanel(final SwingGUI window) {
super(window);
// listen for new status messages
getWindow().getStatusService().addStatusListener(new StatusChangeListener());
this.setup();
}
private final void setup() {
setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
this.statusList = new StatusList(maxMessages);
this.statusList.setLayoutOrientation(JList.VERTICAL);
this.statusList.setVisibleRowCount(maxMessages);
this.statusListScrollPane = new JScrollPane(this.statusList,
ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
c.gridx = 0;
c.gridy = 0;
c.fill = GridBagConstraints.BOTH;
c.weightx = 1;
c.weighty = 1;
c.anchor = GridBagConstraints.FIRST_LINE_START;
c.insets = new Insets(0, 5, 2, 5);
add(this.statusListScrollPane, c);
this.expandButton = new JButton("\u2193");
this.unexpandButton = new JButton("\u2191");
this.unexpandButton.setVisible(false);
this.expandButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StatusPanel.this.expand();
}
});
this.unexpandButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StatusPanel.this.unexpand();
}
});
// make the two buttons the same size
Dimension expandButtonSize = this.expandButton.getPreferredSize();
Dimension unexpandButtonSize = this.unexpandButton.getPreferredSize();
Dimension newSize = new Dimension(expandButtonSize.width > unexpandButtonSize.width ? expandButtonSize.width : unexpandButtonSize.width,
expandButtonSize.height > unexpandButtonSize.height ? expandButtonSize.height : unexpandButtonSize.height);
this.expandButton.setPreferredSize(newSize);
this.expandButton.setMinimumSize(newSize);
this.expandButton.setMaximumSize(newSize);
this.unexpandButton.setPreferredSize(newSize);
this.unexpandButton.setMinimumSize(newSize);
this.unexpandButton.setMaximumSize(newSize);
c.gridx = 1;
c.gridy = 0;
c.fill = GridBagConstraints.NONE;
c.weightx = 0;
c.weighty = 0;
c.anchor = GridBagConstraints.LAST_LINE_END;
c.insets = new Insets(0, 0, 2, 5);
add(this.expandButton, c);
add(this.unexpandButton, c);
}
/**
* {@inheritDoc}
*/
@Override
protected void onInit() {
// TODO Auto-generated method stub
}
/**
* {@inheritDoc}
*/
@Override
protected void onHide() {
// TODO Auto-generated method stub
}
/**
* {@inheritDoc}
*/
@Override
protected void onShow() {
// TODO Auto-generated method stub
}
/**
* {@inheritDoc}
*/
@Override
protected void onQuit() {
// do nothing
}
/**
* {@inheritDoc}
*/
@Override
protected void loadState() {
// TODO Auto-generated method stub
}
/**
* {@inheritDoc}
*/
@Override
protected void saveState() {
// TODO Auto-generated method stub
}
/**
* Expands the StatusPanel (and thus the main window) in order to allow the display
* of multiple {@link StatusService.StatusMessage}s at the same time.
*
* @see #unexpand()
*/
protected final void expand() {
if (this.isExpanded)
throw new IllegalStateException("already expanded");
this.statusList.setVisibleRowCount(maxMessages);
this.expandButton.setVisible(false);
this.unexpandButton.setVisible(true);
Dimension panelDimensions = getPreferredSize();
panelDimensions.height += expandBy;
setPreferredSize(panelDimensions);
// tell the main window to update (StatusPanel is now bigger)
getWindow().pack();
this.isExpanded = true;
}
/**
* Reverts a previous expansion so that only one message is being shown at any given time,
* making the StatusPanel require less screen real estate.
*
* @see #expand()
*/
protected final void unexpand() {
if (!this.isExpanded)
throw new IllegalStateException("not expanded");
this.statusList.setVisibleRowCount(1);
this.expandButton.setVisible(true);
this.unexpandButton.setVisible(false);
Dimension panelDimensions = getPreferredSize();
panelDimensions.height -= expandBy;
setPreferredSize(panelDimensions);
// tell the main window to update (StatusPanel is now smaller)
getWindow().pack();
this.isExpanded = false;
}
/**
* Getter for the {@link StatusList} instance used by this {@link StatusPanel}
*
* @return the {@link StatusList} instance used by this {@link StatusPanel}
*/
protected final StatusList getStatusList() {
return this.statusList;
}
/**
* Listens for new {@link StatusService.StatusMessage}s and adds them to the list.
*
* @author Martin Riedel
*
*/
private class StatusChangeListener implements StatusService.StatusChangeListener {
/**
* Constructs a new instance
*
*/
public StatusChangeListener() {
// do nothing, just allow instantiation
}
/**
* {@inheritDoc}
*/
@Override
public void newStatusMessage(final StatusMessage message) {
StatusPanel.this.getStatusList().addMessage(message);
// reset the scroll pane so that the new message is visible
StatusPanel.this.statusListScrollPane.getVerticalScrollBar().setValue(StatusPanel.this.statusListScrollPane.getVerticalScrollBar().getMinimum());
}
}
}