using Java programming language on the Alice Programming environment » Flamingo
ID: 3751937 • Letter: U
Question
using Java programming language on the Alice Programming environment
» Flamingo on a Table Create a world with a flamingo and a table The flamingo should be facing the table, standing next to it. When the world starts, the flamingo should simultaneously flap its wings and move up in the air a distance that is exactly one-half meter higher than the height of the table. The flamingo should then move forward to approximately the center of the table; then it should move down to the surface of the tableExplanation / Answer
package org.pushingpixels.flamingo.api.ribbon;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ActionListener;
import java.util.*;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import org.pushingpixels.flamingo.api.common.*;
import org.pushingpixels.flamingo.api.common.icon.ResizableIcon;
import org.pushingpixels.flamingo.internal.ui.ribbon.BasicRibbonUI;
import org.pushingpixels.flamingo.internal.ui.ribbon.RibbonUI;
/**
* The ribbon component.
* <p/>
* <p>
* The ribbon has the following major parts:
* </p>
* <ul>
* <li>Ribbon tasks added with {@link #addTask(RibbonTask)}</li>
* <li>Contextual ribbon task groups added with
* {@link #addContextualTaskGroup(RibbonContextualTaskGroup)}</li>
* <li>Application menu button set by
* {@link #setApplicationMenu(RibbonApplicationMenu)}</li>
* <li>Taskbar panel populated by {@link #addTaskbarComponent(Component)}</li>
* <li>Help button set by {@link #configureHelp(ResizableIcon, ActionListener)}</li>
* </ul>
* <p/>
* <p>
* While multiple ribbon tasks can be added to the ribbon, only one is visible
* at any given time. This task is called the <strong>selected</strong> task.
* Tasks can be switched with the task buttons placed along the top part of the
* ribbon. Once a task has been added to the ribbon, it cannot be removed.
* </p>
* <p/>
* <p>
* The contextual ribbon task groups allow showing and hiding ribbon tasks based
* on the current selection in the application. For example, Word only shows the
* table tasks when a table is selected in the document. By default, tasks
* belonging to the groups adde by
* {@link #addContextualTaskGroup(RibbonContextualTaskGroup)} are not visible.
* To show the tasks belonging to the specific group, call
* {@link #setVisible(RibbonContextualTaskGroup, boolean)} API. Note that you
* can have multiple task groups visible at the same time.
* </p>
* <p/>
* <p>
* The application menu button is a big round button shown in the top left
* corner of the ribbon. If the
* {@link #setApplicationMenu(RibbonApplicationMenu)} is not called, or called
* with the <code>null</code> value, the application menu button is not shown,
* and ribbon task buttons are shifted to the left.
* </p>
* <p/>
* <p>
* The taskbar panel allows showing controls that are visible no matter what
* ribbon task is selected. To add a taskbar component use the
* {@link #addTaskbarComponent(Component)} API. The taskbar panel lives to the
* right of the application menu button. Taskbar components can be removed with
* the {@link #removeTaskbarComponent(Component)} API.
* </p>
* <p/>
* <p>
* The ribbon can be minimized in one of the following ways:
* </p>
* <ul>
* <li>Calling {@link #setMinimized(boolean)} with <code>true</code>.</li>
* <li>User double-clicking on a task button.</li>
* <li>User pressing <code>Ctrl+F1</code> key combination.</li>
* </ul>
* <p/>
* <p>
* A minimized ribbon shows the application menu button, taskbar panel, task
* buttons and help button, but not the ribbon bands of the selected task.
* Clicking a task button shows the ribbon bands of that task in a popup
* <strong>without</strong> shifting the application content down.
* </p>
*
* @author Kirill Grouchnikov
*/
public class JRibbon extends JComponent
{
/**
* The general tasks.
*
* @see #addTask(RibbonTask)
* @see #getTaskCount()
* @see #getTask(int)
*/
private ArrayList<RibbonTask> tasks;
/**
* The contextual task groups.
*
* @see #addContextualTaskGroup(RibbonContextualTaskGroup)
* @see #setVisible(RibbonContextualTaskGroup, boolean)
* @see #isVisible(RibbonContextualTaskGroup)
* @see #getContextualTaskGroupCount()
* @see #getContextualTaskGroup(int)
*/
private ArrayList<RibbonContextualTaskGroup> contextualTaskGroups;
/**
* The taskbar components (to the right of the application menu button).
*
* @see #addTaskbarComponent(Component)
* @see #getTaskbarComponents()
* @see #removeTaskbarComponent(Component)
*/
private ArrayList<Component> taskbarComponents;
/**
* Bands of the currently shown task.
*/
private ArrayList<AbstractRibbonBand> bands;
/**
* Currently selected (shown) task.
*/
private RibbonTask currentlySelectedTask;
/**
* Help icon. When not <code>null</code>, the ribbon will display a help
* button at the far right of the tab area.
*
* @see #helpActionListener
* @see #configureHelp(ResizableIcon, ActionListener)
* @see #getHelpIcon()
*/
private ResizableIcon helpIcon;
/**
* When the {@link #helpIcon} is not <code>null</code>, this listener will
* be invoked when the user activates the help button.
*
* @see #configureHelp(ResizableIcon, ActionListener)
* @see #getHelpActionListener()
*/
private ActionListener helpActionListener;
/**
* Visibility status of the contextual task group. Must contain a value for
* each group in {@link #contextualTaskGroups}.
*
* @see #setVisible(RibbonContextualTaskGroup, boolean)
* @see #isVisible(RibbonContextualTaskGroup)
*/
private final Map<RibbonContextualTaskGroup, Boolean> groupVisibilityMap;
/**
* The application menu.
*
* @see #setApplicationMenu(RibbonApplicationMenu)
* @see #getApplicationMenu()
*/
private RibbonApplicationMenu applicationMenu;
/**
* The rich tooltip of {@link #applicationMenu} button.
*
* @see #applicationMenu
* @see #setApplicationMenuRichTooltip(RichTooltip)
* @see #getApplicationMenuRichTooltip()
*/
private RichTooltip applicationMenuRichTooltip;
/**
* The key tip of {@link #applicationMenu} button.
*
* @see #applicationMenu
* @see #setApplicationMenuKeyTip(String)
* @see #getApplicationMenuKeyTip()
*/
private String applicationMenuKeyTip;
/**
* Indicates whether the ribbon is currently minimized.
*
* @see #setMinimized(boolean)
* @see #isMinimized()
*/
private boolean isMinimized;
/**
* The host ribbon frame. Is <code>null</code> when the ribbon is not hosted
* in a {@link JRibbonFrame}.
*/
private JRibbonFrame ribbonFrame;
/**
* The UI class ID string.
*/
public static final String uiClassID = "RibbonUI";
/**
* Creates a new empty ribbon. Applications are highly encouraged to use
* {@link JRibbonFrame} and access the ribbon with
* {@link JRibbonFrame#getRibbon()} API.
*/
public JRibbon()
{
this.tasks = new ArrayList<RibbonTask>();
this.contextualTaskGroups = new ArrayList<RibbonContextualTaskGroup>();
this.taskbarComponents = new ArrayList<Component>();
this.bands = new ArrayList<AbstractRibbonBand>();
this.currentlySelectedTask = null;
this.groupVisibilityMap = new HashMap<RibbonContextualTaskGroup, Boolean>();
updateUI();
}
/**
* Creates an empty ribbon for the specified ribbon frame.
*
* @param ribbonFrame Host ribbon frame.
*/
JRibbon(JRibbonFrame ribbonFrame)
{
this();
this.ribbonFrame = ribbonFrame;
}
/**
* Adds the specified taskbar component to this ribbon.
*
* @param comp The taskbar component to add.
* @see #removeTaskbarComponent(Component)
* @see #getTaskbarComponents()
*/
public synchronized void addTaskbarComponent(Component comp)
{
if (comp instanceof AbstractCommandButton)
{
AbstractCommandButton button = (AbstractCommandButton) comp;
button.setDisplayState(CommandButtonDisplayState.SMALL);
button.setGapScaleFactor(0.5);
button.setFocusable(false);
}
this.taskbarComponents.add(comp);
this.fireStateChanged();
}
/**
* Removes the specified taskbar component from this ribbon.
*
* @param comp The taskbar component to remove.
* @see #addTaskbarComponent(Component)
* @see #getTaskbarComponents()
*/
public synchronized void removeTaskbarComponent(Component comp)
{
this.taskbarComponents.remove(comp);
this.fireStateChanged();
}
/**
* Adds the specified task to this ribbon.
*
* @param task The ribbon task to add.
* @see #addContextualTaskGroup(RibbonContextualTaskGroup)
* @see #getTaskCount()
* @see #getTask(int)
*/
public synchronized void addTask(RibbonTask task)
{
task.setRibbon(this);
this.tasks.add(task);
if (this.tasks.size() == 1)
{
this.setSelectedTask(task);
}
this.fireStateChanged();
}
/**
* Configures the help button of this ribbon.
*
* @param helpIcon The icon for the help button.
* @param helpActionListener The action listener for the help button.
* @see #getHelpIcon()
* @see #getHelpActionListener()
*/
public synchronized void configureHelp(ResizableIcon helpIcon, ActionListener helpActionListener)
{
this.helpIcon = helpIcon;
this.helpActionListener = helpActionListener;
this.fireStateChanged();
}
/**
* Returns the icon for the help button. Will return <code>null</code> if
* the help button has not been configured with the
* {@link #configureHelp(ResizableIcon, ActionListener)} API.
*
* @return The icon for the help button.
* @see #configureHelp(ResizableIcon, ActionListener)
* @see #getHelpActionListener()
*/
public ResizableIcon getHelpIcon()
{
return this.helpIcon;
}
/**
* Returns the action listener for the help button. Will return
* <code>null</code> if the help button has not been configured with the
* {@link #configureHelp(ResizableIcon, ActionListener)} API.
*
* @return The action listener for the help button.
* @see #configureHelp(ResizableIcon, ActionListener)
* @see #getHelpIcon()
*/
public ActionListener getHelpActionListener()
{
return this.helpActionListener;
}
/**
* Adds the specified contextual task group to this ribbon.
*
* @param group Task group to add.
* @see #addTask(RibbonTask)
* @see #setVisible(RibbonContextualTaskGroup, boolean)
* @see #isVisible(RibbonContextualTaskGroup)
*/
public void addContextualTaskGroup(RibbonContextualTaskGroup group)
{
group.setRibbon(this);
contextualTaskGroups.add(group);
groupVisibilityMap.put(group, false);
fireStateChanged();
}
/**
* Returns the number of regular tasks in <code>this</code> ribbon.
*
* @return Number of regular tasks in <code>this</code> ribbon.
* @see #getTask(int)
* @see #addTask(RibbonTask)
*/
public int getTaskCount()
{
return this.tasks.size();
}
/**
* Retrieves the regular task at specified index.
*
* @param index Task index.
* @return Task that matches the specified index.
* @see #getTaskCount()
* @see #addTask(RibbonTask)
*/
public RibbonTask getTask(int index)
{
return this.tasks.get(index);
}
/**
* Returns the number of contextual task groups in <code>this</code> ribbon.
*
* @return Number of contextual task groups in <code>this</code> ribbon.
* @see #addContextualTaskGroup(RibbonContextualTaskGroup)
* @see #getContextualTaskGroup(int)
*/
public int getContextualTaskGroupCount()
{
return contextualTaskGroups.size();
}
/**
* Retrieves contextual task group at specified index.
*
* @param index Group index.
* @return Group that matches the specified index.
* @see #addContextualTaskGroup(RibbonContextualTaskGroup)
* @see #getContextualTaskGroupCount()
*/
public RibbonContextualTaskGroup getContextualTaskGroup(int index)
{
return contextualTaskGroups.get(index);
}
/**
* Remove contextual group
*
* @param group
*/
public void removeContextualTaskGroup(RibbonContextualTaskGroup group)
{
if (group == null)
{
throw new NullPointerException();
}
setVisible(group, false);
contextualTaskGroups.remove(group);
groupVisibilityMap.remove(group);
}
/**
* Selects the specified task. The task can be either regular (added with
* {@link #addTask(RibbonTask)}) or a task in a visible contextual task
* group (added with
* {@link #addContextualTaskGroup(RibbonContextualTaskGroup)}. Fires a
* <code>selectedTask</code> property change event.
*
* @param task Task to select.
* @throws IllegalArgumentException If the specified task is not in the ribbon or not visible.
* @see #getSelectedTask()
*/
public synchronized void setSelectedTask(RibbonTask task)
{
boolean valid = this.tasks.contains(task);
if (!valid)
{
for (int i = 0; i < this.getContextualTaskGroupCount(); i++)
{
RibbonContextualTaskGroup group = this.getContextualTaskGroup(i);
if (!this.isVisible(group))
{
continue;
}
for (int j = 0; j < group.getTaskCount(); j++)
{
if (group.getTask(j) == task)
{
valid = true;
break;
}
}
if (valid)
{
break;
}
}
}
if (!valid)
{
throw new IllegalArgumentException("The specified task to be selected is either not " + "part of this ribbon or not marked as visible");
}
for (AbstractRibbonBand ribbonBand : this.bands)
{
ribbonBand.setVisible(false);
}
this.bands.clear();
for (int i = 0; i < task.getBandCount(); i++)
{
AbstractRibbonBand ribbonBand = task.getBand(i);
ribbonBand.setVisible(true);
this.bands.add(ribbonBand);
}
RibbonTask old = this.currentlySelectedTask;
this.currentlySelectedTask = task;
this.revalidate();
this.repaint();
this.firePropertyChange("selectedTask", old, this.currentlySelectedTask);
}
/**
* Returns the currently selected task.
*
* @return The currently selected task.
* @see #setSelectedTask(RibbonTask)
*/
public synchronized RibbonTask getSelectedTask()
{
return this.currentlySelectedTask;
}
/*
* (non-Javadoc)
*
* @see javax.swing.JComponent#updateUI()
*/
@Override
public void updateUI()
{
if (UIManager.get(getUIClassID()) != null)
{
setUI(UIManager.getUI(this));
}
else
{
setUI(new BasicRibbonUI());
}
for (Component comp : this.taskbarComponents)
{
SwingUtilities.updateComponentTreeUI(comp);
}
}
/**
* Returns the UI object which implements the L&F for this component.
*
* @return a <code>RibbonUI</code> object
* @see #setUI
*/
public RibbonUI getUI()
{
return (RibbonUI) ui;
}
/*
* (non-Javadoc)
*
* @see javax.swing.JComponent#getUIClassID()
*/
@Override
public String getUIClassID()
{
return uiClassID;
}
/**
* Gets an unmodifiable list of all taskbar components of <code>this</code>
* ribbon.
*
* @return All taskbar components of <code>this</code> ribbon.
* @see #addTaskbarComponent(Component)
* @see #removeTaskbarComponent(Component)
*/
public synchronized List<Component> getTaskbarComponents()
{
return Collections.unmodifiableList(this.taskbarComponents);
}
/**
* Adds the specified change listener to track changes to this ribbon.
*
* @param l Change listener to add.
* @see #removeChangeListener(ChangeListener)
*/
public void addChangeListener(ChangeListener l)
{
this.listenerList.add(ChangeListener.class, l);
}
/**
* Removes the specified change listener from tracking changes to this
* ribbon.
*
* @param l Change listener to remove.
* @see #addChangeListener(ChangeListener)
*/
public void removeChangeListener(ChangeListener l)
{
this.listenerList.remove(ChangeListener.class, l);
}
/**
* Notifies all registered listeners that the state of this ribbon has
* changed.
*/
protected void fireStateChanged()
{
// Guaranteed to return a non-null array
Object[] listeners = this.listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
ChangeEvent event = new ChangeEvent(this);
for (int i = listeners.length - 2; i >= 0; i -= 2)
{
if (listeners[i] == ChangeListener.class)
{
((ChangeListener) listeners[i + 1]).stateChanged(event);
}
}
}
/**
* Sets the visibility of ribbon tasks in the specified contextual task
* group. Visibility of all ribbon tasks in the specified group is affected.
* Note that the ribbon can show ribbon tasks of multiple groups at the same
* time.
*
* @param group Contextual task group.
* @param isVisible If <code>true</code>, all ribbon tasks in the specified group
* will be visible. If <code>false</code>, all ribbon tasks in
* the specified group will be hidden.
* @see #isVisible(RibbonContextualTaskGroup)
*/
public void setVisible(RibbonContextualTaskGroup group, boolean isVisible)
{
if (!groupVisibilityMap.containsKey(group))
{
return;
}
this.groupVisibilityMap.put(group, isVisible);
// special handling of selected tab
if (!isVisible)
{
boolean isSelectedBeingHidden = false;
for (int i = 0; i < group.getTaskCount(); i++)
{
if (this.getSelectedTask() == group.getTask(i))
{
isSelectedBeingHidden = true;
break;
}
}
if (isSelectedBeingHidden)
{
this.setSelectedTask(this.getTask(0));
}
}
this.fireStateChanged();
this.revalidate();
SwingUtilities.getWindowAncestor(this).repaint();
}
/**
* Returns the visibility of ribbon tasks in the specified contextual task
* group.
*
* @param group Contextual task group.
* @return <code>true</code> if the ribbon tasks in the specified group are
* visible, <code>false</code> otherwise.
*/
public synchronized boolean isVisible(RibbonContextualTaskGroup group)
{
return this.groupVisibilityMap.get(group);
}
/**
* Sets the application menu for this ribbon. If <code>null</code> is
* passed, the application menu button is hidden. Fires an
* <code>applicationMenu</code> property change event.
*
* @param applicationMenu The new application menu. Can be <code>null</code>.
* @see #getApplicationMenu()
*/
public synchronized void setApplicationMenu(RibbonApplicationMenu applicationMenu)
{
RibbonApplicationMenu old = this.applicationMenu;
if (old != applicationMenu)
{
this.applicationMenu = applicationMenu;
if (this.applicationMenu != null)
{
this.applicationMenu.setFrozen();
}
this.firePropertyChange("applicationMenu", old, this.applicationMenu);
}
}
/**
* Returns the application menu of this ribbon.
*
* @return The application menu of this ribbon.
* @see #setApplicationMenu(RibbonApplicationMenu)
*/
public synchronized RibbonApplicationMenu getApplicationMenu()
{
return this.applicationMenu;
}
/**
* Sets the rich tooltip of the application menu button. Fires an
* <code>applicationMenuRichTooltip</code> property change event.
*
* @param tooltip The rich tooltip of the application menu button.
* @see #getApplicationMenuRichTooltip()
* @see #setApplicationMenu(RibbonApplicationMenu)
*/
public synchronized void setApplicationMenuRichTooltip(RichTooltip tooltip)
{
RichTooltip old = this.applicationMenuRichTooltip;
this.applicationMenuRichTooltip = tooltip;
this.firePropertyChange("applicationMenuRichTooltip", old, this.applicationMenuRichTooltip);
}
/**
* Returns the rich tooltip of the application menu button.
*
* @return The rich tooltip of the application menu button.
* @see #setApplicationMenuRichTooltip(RichTooltip)
* @see #setApplicationMenu(RibbonApplicationMenu)
*/
public synchronized RichTooltip getApplicationMenuRichTooltip()
{
return this.applicationMenuRichTooltip;
}
/**
* Sets the key tip of the application menu button. Fires an
* <code>applicationMenuKeyTip</code> property change event.
*
* @param keyTip The new key tip for the application menu button.
* @see #setApplicationMenu(RibbonApplicationMenu)
* @see #getApplicationMenuKeyTip()
*/
public synchronized void setApplicationMenuKeyTip(String keyTip)
{
String old = this.applicationMenuKeyTip;
this.applicationMenuKeyTip = keyTip;
this.firePropertyChange("applicationMenuKeyTip", old, this.applicationMenuKeyTip);
}
/**
* Returns the key tip of the application menu button.
*
* @return The key tip of the application menu button.
* @see #setApplicationMenuKeyTip(String)
* @see #setApplicationMenu(RibbonApplicationMenu)
*/
public synchronized String getApplicationMenuKeyTip()
{
return this.applicationMenuKeyTip;
}
/**
* Returns the indication whether this ribbon is minimized.
*
* @return <code>true</code> if this ribbon is minimized, <code>false</code>
* otherwise.
* @see #setMinimized(boolean)
*/
public synchronized boolean isMinimized()
{
return this.isMinimized;
}
/**
* Changes the minimized state of this ribbon. Fires a
* <code>minimized</code> property change event.
*
* @param isMinimized if <code>true</code>, this ribbon becomes minimized, otherwise
* it is unminimized.
*/
public synchronized void setMinimized(boolean isMinimized)
{
// System.out.println("Ribbon minimized -> " + isMinimized);
boolean old = this.isMinimized;
if (old != isMinimized)
{
this.isMinimized = isMinimized;
this.firePropertyChange("minimized", old, this.isMinimized);
}
}
/**
* Returns the ribbon frame that hosts this ribbon. The result can be
* <code>null</code>.
*
* @return The ribbon frame that hosts this ribbon.
*/
public JRibbonFrame getRibbonFrame()
{
return this.ribbonFrame;
}
/*
* (non-Javadoc)
*
* @see javax.swing.JComponent#setVisible(boolean)
*/
@Override
public void setVisible(boolean flag)
{
if (!flag && (getRibbonFrame() != null))
{
throw new IllegalArgumentException("Can't hide ribbon on JRibbonFrame");
}
super.setVisible(flag);
}
}
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.