/*
* RapidMiner
*
* Copyright (C) 2001-2014 by RapidMiner and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapidminer.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.gui.tools.components;
import java.awt.Point;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractButton;
import com.rapidminer.gui.tour.Step;
/**
* This class creates a speech bubble-shaped JDialog, which can be attache to
* Buttons, either by using its ID or by passing a reference.
* The bubble triggers two events which are obserable by the {@link BubbleListener};
* either if the close button was clicked, or if the corresponding button was used.
* The keys for the title and the text must be of format gui.bubble.XXX.body or gui.bubble.XXX.title .
*
* @author Thilo Kamradt
*
*/
public class BubbleToButton extends BubbleWindow {
private static final long serialVersionUID = 8601169454504964237L;
private ActionListener buttonListener;
private AbstractButton button = null;
private String buttonKey;
/**
* @param owner the {@link Window} on which this {@link BubbleWindow} should be shown.
* @param preferredAlignment offer for alignment but the Class will calculate by itself whether the position is usable
* @param i18nKey of the message which should be shown
* @param buttonKeyToAttach i18nKey of the Button to which this {@link BubbleWindow} should be placed relative to.
*/
public BubbleToButton(Window owner, String nextDockableKey, AlignedSide preferredAlignment, String i18nKey, String buttonKeyToAttach, Object... arguments) {
this(owner, nextDockableKey, preferredAlignment, i18nKey, buttonKeyToAttach, true, arguments);
}
/**
* @param owner the {@link Window} on which this {@link BubbleWindow} should be shown.
* @param preferredAlignment offer for alignment but the Class will calculate by itself whether the position is usable
* @param i18nKey of the message which should be shown
* @param buttonKeyToAttach i18nKey of the Button to which this {@link BubbleWindow} should be placed relative to.
* @param addListener indicates whether the {@link BubbleWindow} closes if the Button was pressed or when another Listener added by a subclass of {@link Step} is fired.
*/
public BubbleToButton(Window owner, String nextDockableKey, AlignedSide preferredAlignment, String i18nKey, String buttonKeyToAttach, boolean addListener, Object... arguments) {
this(owner, nextDockableKey, preferredAlignment, i18nKey, buttonKeyToAttach, addListener, true, arguments);
}
/**
* @param owner the {@link Window} on which this {@link BubbleWindow} should be shown.
* @param preferredAlignment offer for alignment but the Class will calculate by itself whether the position is usable
* @param i18nKey of the message which should be shown
* @param buttonKeyToAttach i18nKey of the Button to which this {@link BubbleWindow} should be placed relative to.
* @param addListener indicates whether the {@link BubbleWindow} closes if the Button was pressed or when another Listener added by a subclass of {@link Step} is fired.
* @param listenToPerspective if true the {@link BubbleWindow} is only in one Perspective viewable else the Bubble will keep their position doesn't matter whether the perspective changes
*/
public BubbleToButton(Window owner, String nextDockableKey, AlignedSide preferredAlignment, String i18nKey, String buttonKeyToAttach, boolean addListener, boolean listenToPerspective, Object... arguments) {
super(owner, preferredAlignment, i18nKey, nextDockableKey, arguments);
if (preferredAlignment != AlignedSide.MIDDLE) {
//Bubble will be bind to a Component
this.buttonKey = buttonKeyToAttach;
if (buttonKey == null || buttonKey.equals("")) {
throw new IllegalArgumentException("key of the Button can not be null if the Alignment is not MIDDLE");
} else {
this.button = BubbleWindow.findButton(buttonKey, owner);
if (addListener) {
this.addListenerToButton(button);
}
}
}
setAddPerspectiveListener(listenToPerspective);
super.paint(false);
}
/** Positions the window such that the pointer points to the given button.
* In addition to that, adds an {@link ActionListener} to the button which
* closes the BubbleWindow as soon as the button is pressed and one that
* makes sure that the pointer always points at the right position. */
private void addListenerToButton(AbstractButton button) {
buttonListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
BubbleToButton.this.dispose();
fireEventActionPerformed();
unregisterListenerFromButton();
}
};
button.addActionListener(buttonListener);
}
private void unregisterListenerFromButton() {
button.removeActionListener(buttonListener);
}
private void rearrangeButton() {
AbstractButton localButton = BubbleWindow.findButton(buttonKey, owner);
if (!(this.button.equals(localButton))) {
this.unregisterListenerFromButton();
this.addListenerToButton(localButton);
}
}
@Override
protected void registerMovementListener() {
super.registerMovementListener();
this.registerSpecificListener();
}
@Override
protected void unregisterMovementListener() {
super.unregisterMovementListener();
this.unregisterSpecificListeners();
}
@Override
protected Point getObjectLocation() {
return button.getLocationOnScreen();
}
@Override
protected int getObjectWidth() {
return button.getWidth();
}
@Override
protected int getObjectHeight() {
return button.getHeight();
}
@Override
protected void reloadComponent() {
super.reloadComponent();
this.rearrangeButton();
}
@Override
protected void unregisterSpecificListeners() {
}
@Override
protected void registerSpecificListener() {
}
}