/**
* Copyright (C) 2015 Valkyrie RCP
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.valkyriercp.command.support;
import org.springframework.core.style.ToStringCreator;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.valkyriercp.command.config.CommandButtonConfigurer;
import org.valkyriercp.command.config.CommandFaceDescriptor;
import javax.swing.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.ref.WeakReference;
import java.util.HashSet;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
public class CommandFaceButtonManager implements PropertyChangeListener {
private Set buttons = new HashSet(6);
private AbstractCommand command;
private String faceDescriptorId;
private CommandFaceDescriptor faceDescriptor;
private static class ManagedButton {
private WeakReference buttonHolder;
private CommandButtonConfigurer buttonConfigurer;
private int hashCode;
public ManagedButton(AbstractButton button, CommandButtonConfigurer buttonConfigurer) {
this.buttonHolder = new WeakReference(button);
this.buttonConfigurer = buttonConfigurer;
this.hashCode = button.hashCode();
}
public AbstractButton getButton() {
return (AbstractButton)buttonHolder.get();
}
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (this == o) {
return true;
}
return ObjectUtils.nullSafeEquals(getButton(), ((ManagedButton) o).getButton());
}
public int hashCode() {
return hashCode;
}
}
public CommandFaceButtonManager(AbstractCommand command, String faceDescriptorKey) {
Assert.notNull(command, "The command to manage buttons for cannot be null");
Assert.hasText(faceDescriptorKey, "The face descriptor key is required");
this.command = command;
this.faceDescriptorId = faceDescriptorKey;
}
public CommandFaceButtonManager(AbstractCommand command, CommandFaceDescriptor faceDescriptor) {
this.command = command;
setFaceDescriptor(faceDescriptor);
}
public void setFaceDescriptor(CommandFaceDescriptor faceDescriptor) {
Assert.notNull(faceDescriptor, "The face descriptor for managing command button appearance is required");
if (!ObjectUtils.nullSafeEquals(this.faceDescriptor, faceDescriptor)) {
if (this.faceDescriptor != null) {
this.faceDescriptor.removePropertyChangeListener(this);
}
this.faceDescriptor = faceDescriptor;
this.faceDescriptor.addPropertyChangeListener(this);
propertyChange(null);
}
}
public CommandFaceDescriptor getFaceDescriptor() {
return faceDescriptor;
}
public boolean isFaceConfigured() {
return this.faceDescriptor != null;
}
public void attachAndConfigure(AbstractButton button, CommandButtonConfigurer strategy) {
Assert.notNull(button, "The button to attach and configure is required");
Assert.notNull(strategy, "The button configuration strategy is required");
if (!isAttachedTo(button)) {
ManagedButton managedButton = new ManagedButton(button, strategy);
if (buttons.add(managedButton)) {
configure(button, strategy);
}
}
}
private void cleanUp() {
for (Iterator i = buttons.iterator(); i.hasNext();) {
ManagedButton button = (ManagedButton)i.next();
if (button.getButton() == null) {
i.remove();
}
}
}
protected void configure(AbstractButton button, CommandButtonConfigurer strategy) {
if (this.faceDescriptor == null) {
if (command.getFaceDescriptorRegistry() != null) {
setFaceDescriptor(command.getFaceDescriptorRegistry().getFaceDescriptor(command, faceDescriptorId));
} else {
setFaceDescriptor(new CommandFaceDescriptor());
}
}
getFaceDescriptor().configure(button, command, strategy);
}
public void detach(AbstractButton button) {
buttons.remove(findManagedButton(button));
}
public void detachAll() {
buttons.clear();
}
public boolean isAttachedTo(AbstractButton button) {
return findManagedButton(button) != null;
}
protected ManagedButton findManagedButton(AbstractButton button) {
Assert.notNull(button, "The button is required");
cleanUp();
for (Iterator i = buttons.iterator(); i.hasNext();) {
ManagedButton managedButton = (ManagedButton)i.next();
if (button.equals(managedButton.getButton())) {
return managedButton;
}
}
return null;
}
public Iterator iterator() {
cleanUp();
return new ButtonIterator(buttons.iterator());
}
private static class ButtonIterator implements Iterator {
private Iterator it;
private AbstractButton nextButton;
public ButtonIterator(Iterator it) {
this.it = it;
fetchNextButton();
}
public boolean hasNext() {
return nextButton != null;
}
public Object next() {
if (nextButton == null) {
throw new NoSuchElementException();
}
AbstractButton lastButton = nextButton;
fetchNextButton();
return lastButton;
}
public void remove() {
throw new UnsupportedOperationException();
}
private void fetchNextButton() {
while (it.hasNext()) {
ManagedButton managedButton = (ManagedButton)it.next();
nextButton = managedButton.getButton();
if (nextButton != null) {
return;
}
}
nextButton = null;
}
}
public void propertyChange(PropertyChangeEvent e) {
Iterator it = buttons.iterator();
while (it.hasNext()) {
ManagedButton mb = (ManagedButton)it.next();
Assert.notNull(mb, "Managed button reference cannot be null");
if (mb.getButton() == null) {
it.remove();
}
else {
configure(mb.getButton(), mb.buttonConfigurer);
}
}
}
public String toString() {
return new ToStringCreator(this).append("commandId", command.getId())
.append("faceDescriptor", faceDescriptor)
.append("attachedButtonCount", buttons.size())
.toString();
}
}