/* * Tiled Map Editor, (c) 2004-2006 * * This program 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 2 of the License, or * (at your option) any later version. * * Adam Turk <aturk@biggeruniverse.com> * Bjorn Lindeijer <bjorn@lindeijer.nl> */ package tiled.mapeditor.widget; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Frame; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.ActionEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.prefs.Preferences; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSplitPane; import javax.swing.border.EmptyBorder; import tiled.util.TiledConfiguration; /** * A floatable panel. The panel has a titlebar which displays the panel title * plus a small button which can be used to turn the panel into a frame. When * the frame is closed the panel is restored. * * // todo: Prettify the user interface * * @version $Id$ */ public class FloatablePanel extends JPanel { /** * */ private static final long serialVersionUID = -5919167759758549835L; private final JLabel titleLabel; private JDialog frame; private final JComponent child; private final Frame parent; private final Preferences prefs; private int dividerSize; /** * Constructs a floatable panel with the given title. When the panel is * floated, it is placed in a {@link JDialog} with <code>parent</code> as * its parent. * * @param parent the parent of the child * @param child the child component * @param title the title of this panel * @param preferencesId the unique identifier for this panel */ public FloatablePanel(Frame parent, JComponent child, String title, String preferencesId) { this.child = child; this.parent = parent; titleLabel = new JLabel(title); prefs = TiledConfiguration.node("dock/" + preferencesId); final JButton floatButton = new JButton("Float"); floatButton.setAction(new AbstractAction() { /** * */ private static final long serialVersionUID = -8816527727997693543L; public void actionPerformed(ActionEvent e) { setFloating(true); } }); JPanel topPanel = new HeaderPanel(new BorderLayout()); topPanel.add(titleLabel, BorderLayout.WEST); topPanel.add(floatButton, BorderLayout.EAST); // Start in non-floating state // todo: Immediately restore floating state when found in preferences setLayout(new BorderLayout()); add(topPanel, BorderLayout.NORTH); add(child, BorderLayout.CENTER); dividerSize = 0; frame = null; } private void setFloating(boolean floating) { final JSplitPane splitPane = (JSplitPane) getParent(); if (frame != null && !floating) { // Store the floating frame position and size prefs.putInt("width", frame.getWidth()); prefs.putInt("height", frame.getHeight()); prefs.putInt("x", frame.getX()); prefs.putInt("y", frame.getY()); // De-float the child frame.getContentPane().remove(child); frame.dispose(); frame = null; child.setBorder(null); add(child, BorderLayout.CENTER); setVisible(true); // Restore the old divider location final int dividerLocation = prefs.getInt("dividerLocation", 0); splitPane.setDividerSize(dividerSize); splitPane.setDividerLocation(dividerLocation); } else if (frame == null && floating) { // Remember the current divider size dividerSize = splitPane.getDividerSize(); // Store the divider location in the preferences prefs.putInt("dividerLocation", splitPane.getDividerLocation()); // Hide this panel and remove our child panel setVisible(false); remove(child); splitPane.setDividerSize(0); child.setBorder(new EmptyBorder(5, 5, 5, 5)); // Float the child frame = new JDialog(parent, titleLabel.getText()); frame.getContentPane().add(child); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { setFloating(false); } }); // Restore the floating frame position and size final int lastFrameWidth = prefs.getInt("width", 0); final int lastFrameHeight = prefs.getInt("height", 0); final int lastFrameX = prefs.getInt("x", 0); final int lastFrameY = prefs.getInt("y", 0); if (lastFrameWidth > 0) { frame.setSize(lastFrameWidth, lastFrameHeight); frame.setLocation(lastFrameX, lastFrameY); } else { frame.pack(); frame.setLocationRelativeTo(parent); } frame.setVisible(true); } } /** * Restore the state from the preferences. */ public void restore() { final int dividerLocation = prefs.getInt("dividerLocation", 0); final boolean floating = prefs.getBoolean("floating", false); if (floating) { setFloating(true); } else if (dividerLocation > 0) { final JSplitPane splitPane = (JSplitPane) getParent(); splitPane.setDividerLocation(dividerLocation); } } /** * Save the state to the preferences. */ public void save() { prefs.putBoolean("floating", frame != null); if (frame != null) { prefs.putInt("width", frame.getWidth()); prefs.putInt("height", frame.getHeight()); prefs.putInt("x", frame.getX()); prefs.putInt("y", frame.getY()); } else { final JSplitPane splitPane = (JSplitPane) getParent(); prefs.putInt("dividerLocation", splitPane.getDividerLocation()); } } /** * Sets a new title for this panel. * @param title the new title */ public void setTitle(String title) { titleLabel.setText(title); if (frame != null) { frame.setTitle(title); } } /** * The panel that holds the title label and float button. */ private class HeaderPanel extends JPanel { /** * */ private static final long serialVersionUID = -5026843945529334230L; public HeaderPanel(BorderLayout borderLayout) { super(borderLayout); setBorder(BorderFactory.createEmptyBorder(1, 4, 2, 1)); } @Override protected void paintComponent(Graphics g) { Color backgroundColor = new Color(200, 200, 240); g.setColor(backgroundColor); ((Graphics2D) g).fill(g.getClip()); g.setColor(backgroundColor.darker()); g.drawLine(0, getHeight() - 1, getWidth() - 1, getHeight() - 1); } } }